package com.common.auth.service.impl;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.common.api.enums.EnableStateEnum;
import com.common.api.exception.CommonException;
import com.common.auth.api.dto.RoleDto;
import com.common.auth.api.dto.RoleResourceDto;
import com.common.auth.api.service.RoleResourceService;
import com.common.auth.api.service.RoleService;
import com.common.auth.dao.ResourceMapper;
import com.common.auth.dao.RoleMapper;
import com.common.auth.dao.RoleResourceMapper;
import com.common.auth.dao.UserRoleMapper;
import com.common.auth.po.ResourcePo;
import com.common.auth.po.RolePo;
import com.common.auth.po.RoleResourcePo;
import com.common.auth.po.UserRolePo;
import com.common.auth.util.AuthConstant;
import com.common.util.BeanCopyUtil;
import com.common.util.GenerateSequenceUtil;

import lombok.extern.slf4j.Slf4j;

/**
 * <p>
 * 角色表服务实现类
 * </p>
 *
 * @author system
 */
@Slf4j
@Service
public class RoleServiceImpl extends RoleService {

    @Autowired
    private RoleResourceMapper roleResourceMapper;

    @Autowired
    private RoleResourceService resourceService;
    
    @Autowired
    private UserRoleMapper userRoleMapper;

    @Autowired
    private RoleMapper roleMapper;

    @Autowired
    private ResourceMapper resourceMapper;

	@Override
	public RoleDto getRoleAuth(String roleCode) {
		RoleDto dto=get(roleCode);
//		List<RoleActionDto> actionDtoList=new ArrayList<>();
//		List<RoleActionPo> actionList=roleActionService.list(Wrappers.lambdaQuery(RoleActionPo.class).eq(RoleActionPo::getRoleCode, roleCode));
//		Map<String,String> valueMap=new HashMap<>();
//		actionList.forEach(action->{
//			String actionCode=action.getActionCode();
//			valueMap.put(actionCode, action.getActionValue());
//		});
//		if(!valueMap.isEmpty()) {
//			List<ActionPo> actionPoList=actionService.list(Wrappers.lambdaQuery(ActionPo.class).in(ActionPo::getActionCode, valueMap.keySet()));
//			actionPoList.forEach(action->{
//				RoleActionDto roleActionDto=new RoleActionDto();
//				roleActionDto.setActionCode(action.getActionCode());
//				roleActionDto.setActionDesc(action.getActionDesc());
//				roleActionDto.setActionName(action.getActionName());
//				roleActionDto.setActionValue(valueMap.get(action.getActionCode()));
//				roleActionDto.setHasValue(action.getHasValue());
//				roleActionDto.setMultiple(action.getMultiple());
//				roleActionDto.setRoleCode(roleCode);
//				roleActionDto.setValueRange(action.getValueRange());
//				actionDtoList.add(roleActionDto);
//			});
//		}
//		dto.setActionList(actionDtoList);
		List<RoleResourcePo> resourceList=resourceService.list(Wrappers.lambdaQuery(RoleResourcePo.class).eq(RoleResourcePo::getRoleCode, roleCode));
		dto.setResourceList(BeanCopyUtil.mapList(resourceList,RoleResourceDto.class));
		return dto;
	}

    
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void toggleRoleEnableStatus(String roleCode) {
        try {
            // 校验 roleCode 是否为空或非法
            validateRoleCode(roleCode);
            // 管理员角色默认不能被禁用
            checkProtectedRole(roleCode);
            // 获取角色信息，确保角色存在
            RolePo rolePo = getRolePo(roleCode);
            // 切换角色启用状态
            rolePo.setEnableStateEnum(EnableStateEnum.revert(rolePo.getEnableStateEnum()));
            RoleDto roleDto = new RoleDto();
            BeanCopyUtil.copy(rolePo, roleDto, true);
            // 执行更新操作前记录日志
            log.info("即将更新用户{}的启用状态为{}", roleCode, rolePo.getEnableStateEnum());
            roleMapper.updateById(roleDto);
            log.info("用户{}的启用状态已更新", roleCode);
        } catch (Exception e) {
            log.error("启用/禁用角色出现异常:", e.getMessage());
            throw e;
        }
    }

    private void validateRoleCode(String roleCode) {
        validateField(roleCode, "角色编码");
    }

    private void validateField(String value, String filedName) {
        if (StringUtils.isBlank(value)) {
            throw new CommonException(filedName + "不能为空！");
        }
    }

    private RolePo getRolePo(String roleCode) {
        return Optional.ofNullable(roleMapper.selectOne(new LambdaQueryWrapper<RolePo>().eq(RolePo::getRoleCode, roleCode)))
                .orElseThrow(() -> new CommonException("当前角色不存在！"));
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public int dels(List<String> idList) {
        if (CollectionUtils.isEmpty(idList)) {
            throw new CommonException("请选择要删除的角色！");
        }
        try {
            // 根据角色ID批量查询角色信息
            List<RolePo> rolePos = validateSelectedRoleByDatabase(idList);
            // 检查是否存在管理员角色或者操作工角色，如果存在直接抛出异常
            checkProtectedRolesExistence(rolePos);
            // 使用Set存储角色编码，以去除重复项
            Set<String> roleCodeSet = rolePos.stream().map(RolePo::getRoleCode).collect(Collectors.toSet());
            roleResourceMapper.delete(Wrappers.lambdaQuery(RoleResourcePo.class)
            		.in(RoleResourcePo::getRoleCode, roleCodeSet));
            // 执行批量删除操作角色关联用户
            userRoleMapper.delete(Wrappers.lambdaQuery(UserRolePo.class)
                    .in(UserRolePo::getRoleCode, roleCodeSet));
            // 批量删除角色
            roleMapper.deleteBatchIds(idList);
            return roleCodeSet.size();
        } catch (Exception e) {
            log.error("删除角色过程中出现异常, {}", e.getMessage());
            throw e;
        }

    }


    // 排除受保护的角色
    private void checkProtectedRolesExistence(List<RolePo> rolePos) {
        rolePos.stream()
                .filter(role -> isProtectedRole(role.getRoleCode()))
                .findAny()
                .ifPresent(role -> {
                    String errorMsg = "受保护角色" + role.getRoleCode() + "不允许被删除！";
                    log.error(errorMsg);
                    throw new CommonException(errorMsg);
        });
    }


    /**
     *  判断是否是管理员角色或者操作工角色
     * @param roleCode
     * @return
     */
    private Boolean isProtectedRole(String roleCode) {
        return isRoleExist(roleCode, AuthConstant.ADMIN_ROLE);
    }

    private Boolean isRoleExist(String roleCode, String targetRole) {
        return StringUtils.isNotBlank(roleCode) && Objects.equals(roleCode, targetRole);
    }


    // 删除角色时候根据选择的角色id，批量查询数据库
    private List<RolePo> validateSelectedRoleByDatabase(List<String> idList) {
        List<RolePo> rolePos = roleMapper.selectBatchIds(idList);
        if (CollectionUtils.isEmpty(rolePos)) {
            throw new CommonException("当前角色不存在！");
        }
        return rolePos;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public int add(RoleDto roleDto) {
        try {
            validateAndAddRole(roleDto);
            return 1;
        } catch (Exception e) {
            log.error("添加角色过程中出现异常: {}", e.getMessage());
            throw e;
        }
    }

    private void validateAndAddRole(RoleDto roleDto) {
        // 校验参数
        validateRoleDto(roleDto);
        // 角色编码唯一性校验
        checkRoleCodeUnique(roleDto);
        // 设置默认启用标志
        setDefaultEnableFlag(roleDto);
        // 预编译对象
        prepareRoleDto(roleDto);
        // 添加数据
        roleMapper.insert(roleDto);
    }

    /**
     * 校验角色信息
     *
     * @param roleDto
     */
    private void validateRoleDto(RoleDto roleDto) {
        if (Objects.isNull(roleDto)) {
            throw new CommonException("角色信息不能为空！");
        }
        validateRoleCode(roleDto.getRoleCode());
    }


    private void prepareRoleDto(RoleDto roleDto) {
        if (StringUtils.isBlank(roleDto.getId())) {
            // 自动生成角色ID
            roleDto.setId(GenerateSequenceUtil.generateSequenceNo());
            // 设置创建时间和更新时间
            roleDto.setCreateTime(new Date());
            roleDto.setUpdateTime(new Date());
        } else {
            // 更新操作
            roleDto.setUpdateTime(new Date());
        }
    }


    /**
     * 角色编码唯一性校验
     *
     * @param roleDto
     */
    private void checkRoleCodeUnique(RoleDto roleDto) {
        if (roleMapper.exists(Wrappers.lambdaQuery(RolePo.class).eq(RolePo::getRoleCode, roleDto.getRoleCode()))) {
            throw new CommonException("角色编码不能重复！");
        }
    }


    @Transactional(rollbackFor = Exception.class)
    @Override
    public int modify(RoleDto roleDto) {
        try {
            log.info("开始修改角色，修改的角色编码为：" + roleDto.getRoleCode());
            validateAndModifyRole(roleDto);
            log.info("角色修改完成！");
            return 1;
        } catch (Exception e) {
            log.error("修改角色过程中出现异常: {}", e.getMessage());
            throw e;
        }
    }

    private void validateAndModifyRole(RoleDto roleDto) {
        // 校验参数
        validateRoleDto(roleDto);
        // 设置默认启用标志
        setDefaultEnableFlag(roleDto);
        // 禁用/启用前，校验用户是否是被保护角色(管理员和操作工)
        checkProtectedRole(roleDto.getRoleCode());
        // 校验角色是否存在
        RolePo rolePo = checkRoleExistence(roleDto);
        // 角色编码不允许修改
        checkRoleCodeModification(roleDto, rolePo);
        prepareRoleDto(roleDto);
        // 更新角色
        roleMapper.updateById(roleDto);
    }


    private void setDefaultEnableFlag(RoleDto roleDto) {
    	// 设置默认启用标志
    	if(StringUtils.isEmpty(roleDto.getEnableStateEnum())) {
    		roleDto.setEnableStateEnum(EnableStateEnum.enable.getEunmCode());
    	}
    }


    private RolePo checkRoleExistence(RoleDto roleDto) {
        return Optional.ofNullable(roleMapper.selectById(roleDto.getId()))
                .orElseThrow(() -> new CommonException("当前要修改的角色不存在！"));
    }

    /**
     * 校验是否是受保护的角色，受保护的角色不允许被禁用或被分配新的权限资源！
     * @param roleCode
     */
    private void checkProtectedRole(String roleCode) {
        if (isProtectedRole(roleCode))  {
            throw new CommonException("受保护的角色" + roleCode + "不能被禁用或被分配新的权限资源！");
        }
    }

    private void checkRoleCodeModification(RoleDto roleDto, RolePo rolePo) {
        checkFieldModification(rolePo.getRoleCode(), roleDto.getRoleCode(), "角色编码");
    }

    private void checkFieldModification(String oldValue, String newValue, String errorMessage) {
        if (!Objects.equals(oldValue, newValue)) {
            throw new CommonException(errorMessage + "不允许修改！");
        }
    }



    @Transactional(rollbackFor = Exception.class)
    @Override
    public void saveRoleAuth(RoleDto roleDto) {
        try {
            // 参数校验
            validateRoleDto(roleDto);
            String roleCode = roleDto.getRoleCode();
            // 校验是否是受保护的角色，受保护的角色不允许被修改权限资源
            checkProtectedRole(roleCode);
            // 删除已经存在的旧数据
            roleResourceMapper.delete(Wrappers.lambdaQuery(RoleResourcePo.class)
            		.eq(RoleResourcePo::getRoleCode, roleCode));
            // 给角色分配新的资源(权限)
            addNewRoleResource(roleCode, roleDto.getResourceList());
        } catch (Exception e) {
            log.error("为角色分配资源的过程中出现异常: {}", e.getMessage());
            throw e;
        }
    }



    private void addNewRoleResource(String roleCode, List<RoleResourceDto> resourceList) {
        if (CollectionUtils.isNotEmpty(resourceList)) {
        	Collection<RoleResourcePo> list=new ArrayList<>();
            // 给角色分配新的资源(权限)
            Set<String> menuCodes = new HashSet<>();
            resourceList.forEach(item -> {
                // 参数校验
                validateResourceItem(item);
                // 防止重复菜单编码
                if (!menuCodes.add(item.getResourceCode())) {
                    throw new CommonException("菜单编码不允许重复！");
                }
                item.setId(GenerateSequenceUtil.generateSequenceNo());
                item.setRoleCode(roleCode);
                list.add(item);
            });
            resourceService.saveBatch(list);
        }
    }


    private void validateResourceItem(RoleResourcePo roleMenuRelationPo) {
        String menuCode = roleMenuRelationPo.getResourceCode();
        if (StringUtils.isEmpty(menuCode)) {
            throw new CommonException("菜单编码不能为空！");
        }
    }

    @Override
    public List<String> getAssignedResourcesByRoleCode(String roleCode) {
        try {
            // 参数校验
            validateRoleCode(roleCode);
            List<String> menuCodesList = new ArrayList<>();
            // 分为管理员角色和非管理员角色
            if (Objects.equals(AuthConstant.ADMIN_ROLE, roleCode)) {
                menuCodesList = handleAdminRole();
            } else {
                menuCodesList = handleOtherRole(roleCode);
            }
            return menuCodesList;
        } catch (Exception e) {
            log.error("根据角色编码查询已分配的权限资源时出现异常: {}", e.getMessage());
            throw e;
        }
    }

    // 处理ADMIN角色的逻辑
    private List<String> handleAdminRole() {
        List<ResourcePo> menuPos = resourceMapper.selectList(Wrappers.emptyWrapper());
        if (CollectionUtils.isEmpty(menuPos)) {
            return new ArrayList<>();
        }
        return menuPos.stream().map(ResourcePo::getResourceCode).collect(Collectors.toList());
    }

    // 处理非ADMIN角色的逻辑
    private List<String> handleOtherRole(String roleCode) {
        List<RoleResourcePo> roleMenuRelationPos =
                roleResourceMapper.selectList(Wrappers.lambdaQuery(RoleResourcePo.class)
                        .eq(RoleResourcePo::getRoleCode, roleCode));

        if (CollectionUtils.isNotEmpty(roleMenuRelationPos)) {
            return roleMenuRelationPos.stream().map(RoleResourcePo::getResourceCode).collect(Collectors.toList());
        }
        // 如果查询结果为空，可以直接返回空列表
        return new ArrayList<>();
    }


    @Override
    public List<String> getSearchKeyList() {
        return Arrays.asList("role_code", "role_name");
    }
}
